package cn.xydpeng.springframework.beans.factory.xml;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import cn.xydpeng.springframework.beans.BeansException;
import cn.xydpeng.springframework.beans.MutablePropertyValues;
import cn.xydpeng.springframework.beans.PropertyValue;
import cn.xydpeng.springframework.beans.factory.config.RuntimeBeanReference;
import cn.xydpeng.springframework.beans.factory.support.AbstractBeanDefinitionReader;
import cn.xydpeng.springframework.beans.factory.support.BeanDefinitionRegistry;
import cn.xydpeng.springframework.beans.factory.support.RootBeanDefinition;
import cn.xydpeng.springframework.core.io.Resource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author xydpeng
 * @version v1.0
 * @date: 2022/10/13
 * @description:
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {


    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    public int loadBeanDefinitions(Resource resource) throws BeansException {
        try {
            InputStream is = resource.getInputStream();
            InputSource inputSource = new InputSource(is);

            return doLoadBeanDefinitions(inputSource, resource);

        } catch (IOException e) {

        }
        return 0;
    }


    @Override
    public int loadBeanDefinitions(String location) throws BeansException {
        Resource resource = getResourceLoader().getResource(location);
        this.loadBeanDefinitions(resource);
        return 0;
    }


    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeansException {
        //TODO 暂且借助hutool工具临时实现
        int succ = 0;
        try {
            Document doc = XmlUtil.readXML(inputSource.getByteStream());
            Element root = doc.getDocumentElement();
            NodeList childNodes = root.getChildNodes();

            for (int i = 0; i < childNodes.getLength(); i++) {
                // 判断元素
                if (!(childNodes.item(i) instanceof Element)) continue;
                // 判断对象
                if (!"bean".equals(childNodes.item(i).getNodeName())) continue;

                // 解析标签
                Element bean = (Element) childNodes.item(i);
                String id = bean.getAttribute("id");
                String name = bean.getAttribute("name");
                String className = bean.getAttribute("class");
                String initMethod = bean.getAttribute("init-method");
                String destroyMethod = bean.getAttribute("destroy-method");
                String scope = bean.getAttribute("scope");
                // 获取 Class，方便获取类中的名称
                Class<?> clazz = Class.forName(className);
                // 优先级 id > name
                String beanName = StrUtil.isNotEmpty(id) ? id : name;
                if (StrUtil.isEmpty(beanName)) {
                    beanName = StrUtil.lowerFirst(clazz.getSimpleName());
                }

                // 定义Bean
                RootBeanDefinition beanDefinition = new RootBeanDefinition(clazz);
                if (initMethod != "") {
                    beanDefinition.setInitMethodName(initMethod);
                }
                if (destroyMethod != "") {
                    beanDefinition.setDestroyMethodName(destroyMethod);
                }
                if(scope!=""){
                    beanDefinition.setScope(scope);
                }
                // 读取属性并填充
                for (int j = 0; j < bean.getChildNodes().getLength(); j++) {
                    if (!(bean.getChildNodes().item(j) instanceof Element)) continue;
                    if (!"property".equals(bean.getChildNodes().item(j).getNodeName())) continue;
                    // 解析标签：property
                    Element property = (Element) bean.getChildNodes().item(j);
                    String attrName = property.getAttribute("name");
                    String attrValue = property.getAttribute("value");
                    String attrRef = property.getAttribute("ref");
                    // 获取属性值：引入对象、值对象
                    Object value = StrUtil.isNotEmpty(attrRef) ? new RuntimeBeanReference(attrRef) : attrValue;
                    // 创建属性信息
                    PropertyValue propertyValue = new PropertyValue(attrName, value);
                    MutablePropertyValues propertyValues = (MutablePropertyValues) beanDefinition.getPropertyValues();
                    propertyValues.addPropertyValue(propertyValue);
                }
                if (getRegistry().containsBeanDefinition(beanName)) {
                    throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
                }
                // 注册 BeanDefinition
                getRegistry().registerBeanDefinition(beanName, beanDefinition);
                succ++;
            }
            return succ;
        } catch (Exception ex) {
            throw new BeansException("doLoadBeanDefinitions error", ex);
        }

    }


}
